首先建立一個用戶資料的實體類以及Service與Repository方便後續認證使用
AppUserEntity.java
@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
@Entity
@Table(name = "_user")
public class AppUserEntity implements UserDetails {
@Id
@GeneratedValue
private Long id;
@Column(unique = true)
private String email;
private String password;
@Enumerated(EnumType.STRING)
private AppUserRole userRole; // 使用者角色(ex: USER或ADMIN等)
public AppUserEntity(String userName, String email, String password, AppUserRole userRole) {
this.userName = userName;
this.email = email;
this.password = password;
this.userRole = userRole;
}
/**
* 用於提供該用戶授權權限集合
* @return 用戶被授權的權限集合
*/
@Override
public Collection<? extends GrantedAuthority> getAuthorities() {
return List.of(new SimpleGrantedAuthority(userRole.name()));
}
@Override
public String getUsername() {
return email;
}
@Override
public String getPassword() {
return password;
}
/**
* 用來判斷使用者的帳戶是否過期
* @return 如果帳戶已過期,返回false,表示使用者不應該被授權,反之則true。
*/
@Override
public boolean isAccountNonExpired() {
return true;
}
/**
* 用來判斷使用者的帳戶是否被鎖定
* @return 如果帳戶被鎖定,返回false,表示使用者不應該被授權。
*/
@Override
public boolean isAccountNonLocked() {
return true;
}
/**
* 用來判斷使用者的認證信息是否過期,例如密碼是否過期
* @return 如果認證信息已過期,返回false,表示使用者不應該被授權。
*/
@Override
public boolean isCredentialsNonExpired() {
return true;
}
/**
* 用來判斷使用者是否啟用,如果使用者已被禁用
* @return 返回false,表示使用者不應該被授權。
*/
@Override
public boolean isEnabled() {
return true;
}
}
UserDetails是一個 Spring Security 用於自定義用戶詳細信息的介面,它要求您實現一組方法,以描述用戶的身份、權限和帳戶狀態。
public enum AppUserRole {
USER,
ADMIN
}
AppUserService.java
@Service
@AllArgsConstructor
public class AppUserService implements UserDetailsService {
private final static String USER_NOT_FOUND_MSG = "user with email %s not found";
private final AppUserRepository appUserRepository;
@Override
public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
return appUserRepository.findByEmail(email)
.orElseThrow(
() -> new UsernameNotFoundException(String.format(USER_NOT_FOUND_MSG, email))
);
}
}
UserDetailsService 的主要職責是通過用戶名查找用戶的詳細信息,然後進行密碼驗證,並根據用戶的權限配置進行授權。
AppUserRepository.java
@Repository
public interface AppUserRepository extends JpaRepository<AppUserEntity, Long> {
Optional<AppUserEntity> findByEmail(String email);
}
接下來新增Security 一些配置
ApplicationConfig.java
@Configuration
@RequiredArgsConstructor
public class ApplicationConfig {
private final AppUserRepository appUserRepository;
/**
* 用於查找用戶詳細信息
* @return userEmail(用戶詳細信息)
*/
@Bean
public UserDetailsService userDetailsService() {
return userEmail -> appUserRepository.findByEmail(userEmail)
.orElseThrow(() -> new UsernameNotFoundException("User not found with email: " + userEmail));
}
/**
* 執行身份驗證的關鍵組件
*/
@Bean
public AuthenticationProvider authenticationProvider() {
DaoAuthenticationProvider authProvider = new DaoAuthenticationProvider();
authProvider.setUserDetailsService(userDetailsService());
authProvider.setPasswordEncoder(passwordEncoder());
return authProvider;
}
/**
* 管理身份驗證的組件
*/
@Bean
public AuthenticationManager authenticationManager(AuthenticationConfiguration config) throws Exception {
return config.getAuthenticationManager();
}
/**
* 以便將用戶密碼進行安全的雜湊存儲
*/
@Bean
public PasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
}
@Configuration
@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http.csrf(AbstractHttpConfigurer::disable) //禁止CSRF(跨站請求偽造)保護。
.authorizeHttpRequests((authorize) -> authorize //對所有訪問HTTP端點的HttpServletRequest進行限制
.requestMatchers(
"/error/**",
"/api/auth/**"
).permitAll() //指定上述匹配規則中的路徑,允許所有用戶訪問,即不需要進行身份驗證。
.anyRequest().authenticated() //其他尚未匹配到的路徑都需要身份驗證
);
return http.build();
}
}
後續會介紹JWT